home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Typography Samples / Basic Layout Sample ƒ / Basic Layout.c next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  19.2 KB  |  564 lines  |  [TEXT/KAHL]

  1. /**\
  2. |**| =====================================================================
  3. |**|
  4. |**|    Glyph Layout.c
  5. |**|
  6. |**|    This file contains the calls that this sample needs to make
  7. |**|    the QuickDraw GX shell work correctly.
  8. |**|
  9. |**|    QuickDraw GX Libraries Used:
  10. |**|    "color library.c", "font library.c", "graphics debug library.c",
  11. |**|    "layout library.c", "shape library.c", and "transform library.c".
  12. |**|
  13. |**|    ©1992-1994  Apple Computer, Inc.
  14. |**|    All rights reserved.
  15. |**|
  16. |**| =====================================================================
  17. \**/
  18. /****************************************************************************/
  19. /*                                                                            */
  20. /*    Basic Layout Sample.c                                                    */
  21. /*                                                                            */
  22. /*    This file contains the calls that an application needs to make            */
  23. /*    the QuickDraw GX shell work correctly.                                    */
  24. /*                                                                            */
  25. /*    QuickDraw GX Libraries Used:                                            */
  26. /*        "color library.c", "font library.c", "graphics debug library.c",    */
  27. /*        "layout library.c", "shape library.c", and "transform library.c".    */ 
  28. /*                                                                            */
  29. /*    Written by Eric Mader and Robert Dierkes                                */
  30. /*                                                                            */
  31. /*     1.0B2  MD  09/09/93        change QDLocalToFixedGlobal to GXConvertQDPoint,*/ 
  32. /*                            including removing validation just for B2        */
  33. /*                                                                            */
  34. /*    ©1992-1994  Apple Computer, Inc.                                        */
  35. /*    All rights reserved.                                                    */
  36. /*                                                                            */
  37. /****************************************************************************/
  38.  
  39. #include "QDGX shell.h"
  40. #include "layout routines.h"
  41. #include "layout library.h"
  42. #include "font menu library.h"
  43.  
  44.  
  45. /**\
  46. |**| ---------------------------------------------------------------------
  47. |**| PROTOTYPES
  48. |**| ---------------------------------------------------------------------
  49. \**/
  50.  
  51. // funtions required by shell
  52.  
  53. void    DoSetup            (void);
  54. void    DoDraw            (WindowPtr wind, Boolean updating);
  55. OSErr    DoCreateNew        (void);
  56. void    DoDispose        (WindowPtr wind);
  57. void    DoIdle            (WindowPtr wind);
  58. void    DoTeardown        (void);
  59. void    DoClick            (WindowPtr wind, Point p);
  60.  
  61. // private functions
  62.  
  63. OSErr    DoWindowInit        (WindowPtr wind);
  64. void    CreateSampleImage    (WindowPtr wind);
  65.  
  66.  
  67. /**\
  68. |**| ---------------------------------------------------------------------
  69. |**| ENUMS
  70. |**| ---------------------------------------------------------------------
  71. \**/
  72. enum { rWindResource = 128, rStartOfHeirMenus=140 };
  73.  
  74.  
  75. /**\
  76. |**| ---------------------------------------------------------------------
  77. |**| GLOBALS
  78. |**| ---------------------------------------------------------------------
  79. \**/
  80. // If gDebugging = TRUE, graphics library errors and notices will be posted.  This
  81. // functionality will only work with the "debugging" version of QuickDraw GX.
  82. // If the debugging version is not installed, nothing bad will happen, but these
  83. // functions will not work. 
  84.  
  85. Boolean        gDebugging = true;
  86.  
  87. // Set  "gGiveMeValidation" to TRUE if you want receive run-time validation.
  88.  
  89. Boolean        gGiveMeValidation = true;
  90.  
  91.  
  92. // gGraphicsHeapSize sets the size of the graphics heap created by calling the
  93. // GXNewGraphicsClient routine in main () within QuickDraw GX shell.c.  You can determine
  94. // the amount of graphics heap required by using GraphicsBug.  I'm giving it 600K,
  95. // since we need abunch if we have several windows open.
  96.  
  97. long        gGraphicsHeapSize = 600;
  98.  
  99. // gOurPrintingOverrideUPP is a universal proc pointer for our printing event
  100. // override.  This is so that our override can be native PowerPC code if necessary.
  101.  
  102. GXPrintingEventUPP    gOurPrintingOverrideUPP;
  103.  
  104.  
  105.  
  106. /**\
  107. |**| ---------------------------------------------------------------------
  108. |**| DoSetup()
  109. |**| Here's where we initialize any global variables our application needs.
  110. |**| We have only one at this time -- the universal proc pointer for
  111. |**| our printing override.
  112. |**| ---------------------------------------------------------------------
  113. \**/
  114. void DoSetup (void)
  115. {    // Initialize our printing event override UPP
  116.     gOurPrintingOverrideUPP = NewGXPrintingEventProc(MyPrintingEventOverride);
  117.  
  118.     EnableItem(GetMHandle(mEdit), 0);
  119.     DisableItem(GetMHandle(mEdit), iUndo);
  120.     EnableItem(GetMHandle(mEdit), iCut);
  121.     EnableItem(GetMHandle(mEdit), iCopy);
  122.     EnableItem(GetMHandle(mEdit), iPaste);
  123.     EnableItem(GetMHandle(mEdit), iClear);
  124.     
  125.     HierFontMenu(    GetMHandle(fontMenuID),
  126.                     rStartOfHeirMenus,
  127.                     (fontFilterProc) nil,
  128.                     noInstancesFontMenu);
  129. }
  130.  
  131.  
  132. /**\
  133. |**| ---------------------------------------------------------------------
  134. |**| DoDraw()
  135. |**| Draw the contents of the window.  The first parameter is the window
  136. |**| to draw, and the second parameter is true if we're updating an existing
  137. |**| image.  If that's the case, we don't want to change anything, but
  138. |**| just draw what's already there.
  139. |**| ---------------------------------------------------------------------
  140. \**/
  141. void DoDraw (WindowPtr wind, Boolean updating)
  142. {
  143.      #pragma unused (updating)
  144. //     GXDrawShape (GetDocShape(wind));
  145.     LayoutEditUpdate( GetDocLEHandle(wind) );
  146. }
  147.  
  148.  
  149. /**\
  150. |**| ---------------------------------------------------------------------
  151. |**| DoCreateNew()
  152. |**| This routine is called when a window needs to be created.
  153. |**| ---------------------------------------------------------------------
  154. \**/
  155. OSErr DoCreateNew (void)
  156. {
  157.     OSErr        err = noErr;
  158.     WindowPtr    wind;
  159.     
  160. // Get and create our window from the resource fork
  161.  
  162.     wind = GetNewWindow(rWindResource, nil, (WindowPtr)-1L);
  163.  
  164. // Attach a default gxViewPort to it, create and iInitialize our
  165. // private data for it, and add a sample image to its page shape.
  166.  
  167.     if ( wind == NULL )
  168.         return (MemError());
  169.  
  170.     GXIgnoreGraphicsNotice(transform_already_set);
  171.     SetDefaultViewPort(GXNewWindowViewPort(wind));            
  172.     GXPopGraphicsNotice();
  173.     
  174.     err = DoWindowInit(wind);
  175.     if ( err != noErr )
  176.         return err;
  177.     
  178.     CreateSampleImage(wind);
  179.     return err;
  180. }
  181.  
  182.  
  183. /**\
  184. |**| ---------------------------------------------------------------------
  185. |**| DoDispose()
  186. |**| This routine is called when a window needs to be disposed of.
  187. |**| ---------------------------------------------------------------------
  188. \**/
  189. void DoDispose (WindowPtr wind)
  190. {
  191.     TH_Doc    doc;
  192.     
  193. // You should always dispose of your GX graphics objects before tossing your window.
  194. // Why?  It's generally good form and this approach guarantees that everything is
  195. // disposed.  If you had not disposed of everything, the call to DisposeWindow should
  196. // dispose of the objects. If you are running the debugging version of QuickDraw GX
  197. // with notices set, you will receive a notice that you had not disposed of everything.
  198. // You can turn notices on in this file by setting gDebugging = TRUE (above).
  199.     
  200.     if ( wind != NULL )
  201.     {
  202.         doc = (TH_Doc)GetWRefCon(wind);        // Remember, this is where we stored our private data.
  203.         GXDisposeShape(GetDocShape(wind));     // Dispose of this doc's shape.
  204.         GXDisposeJob(GetDocJob(wind));        // Dispose of this doc's print job.
  205.         DisposHandle((Handle) doc);            // Dispose of our private data.
  206.         DisposeWindow(wind);                // Dispose of the window.
  207.     }
  208. }
  209.  
  210.  
  211. /**\
  212. |**| ---------------------------------------------------------------------
  213. |**| DoIdle()
  214. |**| This routine is called to do things while idling through the event loop.
  215. |**| ---------------------------------------------------------------------
  216. \**/
  217. void DoIdle (WindowPtr wind)
  218. {
  219.     LayoutEditIdle( GetDocLEHandle(wind) );
  220. }
  221.  
  222.  
  223. /**\
  224. |**| ---------------------------------------------------------------------
  225. |**| DoTeardown()
  226. |**| This routine is called just before we quit to remove anything 
  227. |**| persistent that might have been setup by DoSetup().
  228. |**| ---------------------------------------------------------------------
  229. \**/
  230. void DoTeardown (void)
  231. {
  232.     DisposeRoutineDescriptor(gOurPrintingOverrideUPP);
  233. }
  234.  
  235.  
  236. /**\
  237. |**| ---------------------------------------------------------------------
  238. |**| DoClick()
  239. |**| ---------------------------------------------------------------------
  240. \**/
  241. void DoClick(WindowPtr window, Point p)
  242. {
  243.     gxPoint hitDown;
  244.     gxValidationLevel     currentValidation;
  245.  
  246. //    Unfortunately, GXConvertQDPoint(..) will not survive validation with the QD GX ß2
  247. //    seed. Therefore, we get the validation level set up by the application,  and turn the
  248. //    validation off. We will reset the validation to it's original setting below.
  249. //
  250. //    This problem has already been fixed in the QD GX ß3 build, therefore this work around 
  251. //    will be removed at ß3. Details about the parameters for the GXConvertQDPoint (..) call
  252. //    can be found in the QD GX ß2 Graphics Notes within the "• Open Me First •" folder.
  253.  
  254.     currentValidation = GXGetValidation();
  255.     if (currentValidation) GXSetValidation(gxNoValidation);
  256.     
  257.     /**  Convert the global Quickdraw coordinates to local fixed coordinates.  **/
  258.     GXConvertQDPoint(&p, 0, &hitDown);
  259.  
  260.  
  261. //    Reset the validation to the original setting.
  262.  
  263.     if (currentValidation) GXSetValidation(currentValidation);
  264.  
  265.     LayoutEditClick( GetDocLEHandle(window), hitDown);
  266. }
  267.  
  268.  
  269.  
  270.  
  271.  
  272. /**\
  273. |**| ---------------------------------------------------------------------
  274. |**| DoWindowInit()
  275. |**| In this function we create and initialize the the private document
  276. |**| structure for a new window.  This structure contains the print job and
  277. |**| the shape which is drawn in the window.  We store this data in a handle
  278. |**| and hang it off the window's refCon field for easy retrieval.  By doing
  279. |**| this, rather than using globals, we can create many windows containing
  280. |**| unique print jobs and shapes.
  281. |**| ---------------------------------------------------------------------
  282. \**/
  283. OSErr DoWindowInit (WindowPtr wind)
  284. {
  285.     OSErr    err = noErr;
  286.     gxJob    docJob;
  287.     gxShape    docPage;
  288.     gxShape    docErase;
  289.     TH_Doc    windDoc;
  290.  
  291.  
  292. // Create the page shape. We set the unique items attribute to make sure that each item
  293. // added to the picture has a unique reference. If this attribute was not set, we would
  294. // not see all copies of anything we add to the shape multiple times -- we'd just see
  295. // the last version added.        
  296.  
  297.     docPage = GXNewShape(gxPictureType);
  298.     GXSetShapeAttributes(docPage, (GXGetShapeAttributes(docPage) | gxUniqueItemsShape));
  299.     
  300.     
  301. // Create the erase shape. We set the unique items attribute to make sure that each item
  302. // added to the picture has a unique reference. If this attribute was not set, we would
  303. // not see all copies of anything we add to the shape multiple times -- we'd just see
  304. // the last version added.        
  305.  
  306.     docErase = GXNewShape(gxPictureType);
  307.     GXSetShapeAttributes(docErase, (GXGetShapeAttributes(docErase) | gxUniqueItemsShape));
  308.     
  309.     
  310. // Create a print job for this document.  This will be the same as the system default until
  311. // the user goes through the dialogs for Page Setup or Print…
  312.  
  313.     err = GXNewJob(&docJob);
  314.     
  315.     
  316. // If there are no errors, create a handle the size of our document structure and store
  317. // the print job and page shape in it.  Store the handle in the window's refCon field so
  318. // that we can get at it.  (Note that the utility routines "GetDocJob" and "GetDocShape"
  319. // can be used to do this easily.
  320.  
  321.     if ( err == noErr )
  322.     {
  323.         windDoc = (TH_Doc) NewHandleClear(sizeof(T_Doc));
  324.  
  325.         if ( windDoc == NULL )
  326.             err = MemError();
  327.         else
  328.         {
  329.             (*windDoc)->docJob = docJob;
  330.             (*windDoc)->docPage = docPage;
  331.             (*windDoc)->docLEHandle = nil;
  332.             SetWRefCon(wind, (long) windDoc);
  333.         }
  334.  
  335. // Now install our application override for PrintingEvent so that we can
  336. // support the new movable-modal printing dialog boxes.
  337.  
  338.         GXInstallApplicationOverride(docJob, gxPrintingEvent, gOurPrintingOverrideUPP);
  339.  
  340.     }
  341.  
  342.     return err;
  343. }
  344.  
  345.  
  346. /**\
  347. |**| ---------------------------------------------------------------------
  348. |**| CreateSampleImage()
  349. |**| This function creates primitive shapes and adds them to the window's page shape.
  350. |**| ---------------------------------------------------------------------
  351. \**/
  352. void CreateSampleImage (WindowPtr wind)
  353. {
  354.     Rect    ourWindowRect = wind->portRect; // the rectangle for this window
  355.                                             // in QuickDraw coordinates
  356.     gxShape layout;                        // the layout shape we build
  357.     gxShape thePage;                    // this window's document shape
  358.     gxRunControls runControls;            // run controls for the layout shape
  359.     gxLayoutOptions layoutOptions;        // options for the layout shape
  360.     gxStyle timesStyle;                    // a style record for a Times-based style
  361.     gxStyle hoeflerStyle;                // ditto for Helvetica
  362.     gxStyle baghdadStyle;                 // ditto for Baghdad
  363.     gxStyle textStyles[4];                // an array of text style for our text runs
  364.     
  365. // These are the five text runs for this layout shape, in pieces because they're
  366. // in different languages
  367.     
  368.     char *text1 = "The wicked ";
  369.     char *text2 = "fast ";
  370.     
  371. // The following is "Macintosh" in Arabic: 
  372. // meem, alif, kaf,  noon, tah,  wau,  shin
  373. // (This assumes the standard Arabic character set for Macintosh, by the way)
  374.     
  375.     static char text3[] = {0xE5, 0xC7, 0xE3, 0xE6, 0xCA, 0xE8, 0xD4, 0};
  376.     
  377.     char *text4 = " lives!";
  378.  
  379.  
  380.     char *textRuns[4];                    // an array of pointers to text runs
  381.  
  382.     short textLengths[4];                // an array of the lengths of each run
  383.     short totalLength;                    // the total length of the layout's text
  384. //    static short levelRunLengths[3];    // an array of the lengths of each level
  385. //    static short levels[3] = {0, 1, 0};    // the level numbers for each level
  386.     short levels = 0;
  387.     
  388.     gxPoint posn;                        // the position of the layout shape
  389.  
  390.  
  391. // First, initialize the textRuns array to point to the five text runs
  392.     
  393.     textRuns[0] = text1;
  394.     textRuns[1] = text2;
  395.     textRuns[2] = text3;
  396.     textRuns[3] = text4;
  397.     
  398.     
  399. // Initialize the text lengths.
  400.  
  401.     textLengths[0] = MyStrLength(text1);
  402.     textLengths[1] = MyStrLength(text2);
  403.     textLengths[2] = MyStrLength(text3);
  404.     textLengths[3] = MyStrLength(text4);
  405.     
  406. // Our layout has three levels in it -- level 0 for the English runs at each end,
  407. // and level 1 for the Arabic text in the middle.  We need the byte-count for each
  408. // level's text run in the levelRunLengths array.
  409.  
  410. //    levelRunLengths[0] = textLengths[0];
  411. //    levelRunLengths[1] = textLengths[1] + textLengths[2] + textLengths[3];
  412. //    levelRunLengths[2] = textLengths[4];
  413.  
  414.     
  415. // totalLength is the length of all the text.
  416.  
  417.     totalLength = textLengths[0] + textLengths[1] + textLengths[2] + textLengths[3];
  418.     
  419.  
  420. // make default gxLayoutOptions and gxRunControls structures
  421.  
  422.     InitializeLayoutOptions (&layoutOptions);
  423.     InitializeRunControls (&runControls);
  424.     
  425. // Position the layout half way down the left edge of the window. Set 
  426. // the layout's width to the window's width and set the flushness to 1/2, this
  427. // will cause the layout to center in the window.  Note that ourWindowRect is
  428. // not in fixed coordinates, so we have to make it fixed to use it.
  429.  
  430.     layoutOptions.width = ff(ourWindowRect.right - ourWindowRect.left);
  431.     layoutOptions.flush = fract1/2;
  432.  
  433.     posn.x = 0;
  434.     posn.y = ff((ourWindowRect.bottom - ourWindowRect.top) / 2);
  435.     
  436.  
  437. // Create the styles we'll use.  The helveticaStyle is 30-point Helvetica.
  438. // NewLayoutStyle is a library routine found in layout library.c.  But first,
  439. // this important message:
  440.  
  441. // When I was converting this sample to actually print, I found this strange
  442. // problem that the highlight shape, while appearing correctly on the screen,
  443. // was always too far to the right when printed -- sometimes overlapping parts
  444. // of glyphs that shouldn't be highlighted.  An investigation was launched.
  445. //
  446. // It turns out that highlight shapes are pretty much always 72 DPI, because
  447. // they're polygons calculated from the metrics of the layout shape when the
  448. // highlight shape is created.  If you then scale the layout shape by
  449. // transforming it to 300 DPI or so (like a printer driver would do), the
  450. // highlight shape has the same geometry while hinting of the glyphs may have
  451. // changed the way the layout shape looks.  They've moved a little bit, perhaps,
  452. // and therefore the highlight shape isn't in the right place anymore.
  453. //
  454. // If this is for your on-screen work, you can recreate the highlight shape in
  455. // a zoomed viewPort, but you don't get to make the printer driver do that for
  456. // you.  So, instead, for each style run we use, we add the gxNoMetricsGridText
  457. // attribute.  This prevents QuickDraw GX from using hinting, so the glyphs always
  458. // scale the same way the highlight shape does, and all is well.
  459. //
  460. // (At first, I tried to fix this by adding gxNoMetricsGridShape to the layout
  461. // _shape's_ attributes, but that's not the right idea.  The attributes in the
  462. // shape's style affect any part of the layout that doesn't have a style of its
  463. // own, including any parts of the text for which the entry in the style array
  464. // is nil.  Since we're actually applying styles over the layout here, the
  465. // gxNoMetricsGridText must be set in those styles, not in the shape's style.)
  466. //
  467. // This does mean that your glyphs won't get hinting at low resolutions and
  468. // small point sizes where it might be desirable -- but it's really only a problem
  469. // if you're trying to print a highlight shape, which doesn't happen very often.
  470. // In fact, I can't really think of a legitimate reason to want to do it, except
  471. // maybe in sample code.
  472.     
  473.     hoeflerStyle = NewLayoutStyle(
  474.         (char *) "\pHoefler Text",            // the gxFontName for the style
  475.         ff(30),                                // the text size in fixed point
  476.         gxNoMetricsGridText,                // gxTextAttributes
  477.         &runControls,                        // run controls (our default ones)
  478.         nil,                                // run features (none for this style)
  479.         0,                                    // count of run features
  480.         nil);                                // style run overrides (none right now)
  481.  
  482. // The second style is baghdadStyle -- Baghdad Plain (Arabic), 30 points.
  483.  
  484.     baghdadStyle = NewLayoutStyle(
  485.         (char *) "\pBaghdad Plain",            // gxFontName
  486.         ff(30),                                // text size (fixed point)
  487.         gxNoMetricsGridText,                // gxTextAttributes
  488.         &runControls,                        // run controls (our default ones)
  489.         nil,                                 // run features (none)
  490.         0,                                     // count of run features (none)
  491.         nil);                                // style run overrides (none)
  492.     
  493. // The final style is 30-point Times Roman.
  494.  
  495.     timesStyle = NewLayoutStyle(
  496.         (char *) "\pTimes Roman",             // gxFontName
  497.         ff(30),                             // text size (fixed point)
  498.         gxNoMetricsGridText,                // gxTextAttributes
  499.         &runControls,                         // run controls (our default ones)
  500.         nil,                                 // run features (none)
  501.         0,                                     // count of run features (none)
  502.         nil);                                // style run overrides (none)
  503.     
  504.  
  505. // Initialize the textStyles array so that each of the five runs has the right style
  506.  
  507.     textStyles[0] = hoeflerStyle;
  508.     textStyles[1] = timesStyle;
  509.     textStyles[2] = baghdadStyle;
  510.     textStyles[3] = hoeflerStyle;
  511.     
  512.  
  513. // Setup complete!  Build the layout.
  514.  
  515.     layout = GXNewLayout(
  516.         4,                                // count of text runs
  517.         textLengths,                    // array of lengths of each run
  518.         (void *) textRuns,                // array of pointers to the text
  519.         4,                                // count of style runs
  520.         textLengths,                    // array of the byte lengths of each run
  521.         textStyles,                        // array of the styles
  522.         1,                                // number of levels in the layout
  523.         &totalLength,                    // array of the lengths of each level
  524.         &levels,                        // array of the levels
  525.         &layoutOptions,                    // options (default)
  526.         &posn);                            // position of the layout shape
  527.  
  528.     GXSetShapeStyle(layout, hoeflerStyle);
  529.     
  530.     
  531.     
  532. // Retrieve the page shape so we can add to it.
  533.  
  534.     thePage = GetDocShape(wind);
  535.     
  536. // Add the layout to the window's picture shape.  AddToShape is in shape library.c.
  537.  
  538.     AddToShape(thePage, layout);
  539.  
  540.  
  541. // build LayoutEditHandle and attatch to this windows document
  542. //    layoutHandle = LayoutEditHandleFromLayout(layout);
  543.     if ( wind != NULL )
  544.     {
  545.         TH_Doc    doc = (TH_Doc) GetWRefCon(wind);
  546.         (*doc)->docLEHandle = LayoutEditHandleFromLayout(layout);
  547.     }
  548.  
  549.  
  550. // Dispose of what we allocated
  551.  
  552. //    GXDisposeShape(layout);
  553.     GXDisposeStyle(hoeflerStyle);
  554.     GXDisposeStyle(baghdadStyle);
  555.     GXDisposeStyle(timesStyle);
  556.     
  557.  
  558. // Invalidate the window's portRect so that everything gets updated.
  559.     
  560.     SetPort(wind);
  561.     InvalRect(&ourWindowRect);
  562. }
  563.  
  564.